package cn.alpha.open.autocode.source;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import cn.alpha.open.autocode.AutoCodeException;
import cn.alpha.open.autocode.mavenplugin.DataSourceCfg;
import cn.alpha.open.autocode.model.ColumnMeta;
import cn.alpha.open.autocode.model.TableMeta;

public class TableMetaSource 
{
	private DataSourceCfg dataSourceCfg;
	
	private List<TableMeta> tableMetas;
	
	private SqlDialect dialect;
	
	private DataSource dataSource;
	
	private JdbcTemplate jdbcTemplate;
	
	public TableMetaSource(DataSourceCfg dataSourceCfg)
	{
		this.dataSourceCfg=dataSourceCfg;
		dataSource=new DriverManagerDataSource(dataSourceCfg.getJdbcUrl(), 
				dataSourceCfg.getJdbcUserName(), dataSourceCfg.getJdbcPassword());
		jdbcTemplate=new JdbcTemplate(dataSource);
		
		initDialect();
	}
	
	public void readTableMeta()
	{
		tableMetas=jdbcTemplate.query(dialect.getTableSql(), new RowMapper<TableMeta>() {
			@Override
			public TableMeta mapRow(ResultSet rs, int rowNum) throws SQLException {
				TableMeta table=new TableMeta();
				table.setTableName(rs.getString("tableName"));
				table.setTableComment(rs.getString("tableComment"));
				return table;
			}
		});
		
		String tableName;
		for(final TableMeta tableMeta:tableMetas)
		{
			tableName=tableMeta.getTableName();
			final String pkName=jdbcTemplate.query(dialect.getPKSql(tableName), new ResultSetExtractor<String>() {
				@Override
				public String extractData(ResultSet rs) throws SQLException, DataAccessException {
					return rs.next()?rs.getString("pkName"):null;
				}
			});
			tableMeta.setHasSinglePK(pkName!=null);
			
			tableMeta.setColumnMetas(jdbcTemplate.query(dialect.getColumnSql(tableName),
					new RowMapper<ColumnMeta>() {
						@Override
						public ColumnMeta mapRow(ResultSet rs, int rowNum) throws SQLException {
							ColumnMeta res=new ColumnMeta();
							res.setColumnComment(rs.getString("columnComment"));
							res.setColumnName(rs.getString("columnName"));
							res.setOrdinalPosition(rs.getInt("ordinalPosition"));
							res.setDataType(rs.getString("dataType"));
							res.setNullable(rs.getBoolean("isNullable"));
							res.setDataLength(rs.getLong("dataLength"));
							res.setPrecision(rs.getInt("precision"));
							res.setScale(rs.getInt("scale"));
							
							if(res.getColumnName().equals(pkName))
								tableMeta.setPkColumn(res);
							return res;
						}
					}));
		}
	}

	private void initDialect()
	{
		Connection connection = null;
		try {
			connection = jdbcTemplate.getDataSource().getConnection();
			DatabaseMetaData md = connection.getMetaData();
			if ("Oracle".equalsIgnoreCase(md.getDatabaseProductName())) {
				throw new AutoCodeException("umcompleted");
			} else if ("Microsoft SQL Server".equals(md.getDatabaseProductName()) || "sqlserver".equalsIgnoreCase(md.getDatabaseProductName())) {
				throw new AutoCodeException("umcompleted");
			} else if ("MySql".equalsIgnoreCase(md.getDatabaseProductName())) {
				dialect=new MysqlDialect(dataSourceCfg.getSchema());
			}
		} catch (SQLException e) {
		} finally {
			try {
				if (connection != null) connection.close();
			} catch (SQLException e) {
			}
		}
	}
	
	public List<TableMeta> getTableMetas() {
		return tableMetas;
	}
	
	
}
